﻿using APP.BaseClass;
using APP.Log;
using APP.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using static APP.Win32.Win32Helper;

namespace APP.Windows
{
    public class WindowHelper
    {

        public static Bitmap GetFullScreen()
        {
            Bitmap bmpScreen = null;

            Application.Current.Dispatcher.Invoke(() =>
            {
                Clipboard.Clear();
                Thread.Sleep(300);
                PrintScreen();
                Thread.Sleep(300);
                int count = 0;
                while (count < 10)
                {
                    try
                    {
                        IDataObject iObj = Clipboard.GetDataObject();
                        if (iObj.GetDataPresent(typeof(Bitmap)))
                        {
                            bmpScreen = iObj.GetData(typeof(Bitmap)) as Bitmap;
                        }
                        break;
                    }
                    catch (Exception ex)
                    {
                        Thread.Sleep(300);

                    }
                    count++;
                }
            });
            return bmpScreen;
        }



        /// <summary>
        /// 模拟Print Screen键盘消息。截取全屏图片。
        /// </summary>
        public static void PrintScreen()
        {
            Win32.Win32Helper.keybd_event((byte)0x2c, 0, 0x0, IntPtr.Zero);//down
            System.Windows.Forms.Application.DoEvents();
            Win32.Win32Helper.keybd_event((byte)0x2c, 0, 0x2, IntPtr.Zero);//up
            System.Windows.Forms.Application.DoEvents();
        }

        public static Rectangle FindWindowRect(string proName, string winName, StringCompareType windowsTitleMatchRule
   , ref IntPtr winHwnd, double getParentInaccuracy = 0.3, bool includeMinimizedWindow = false)
        {
            if (proName.EndsWith(".exe"))
            {
                proName = proName.Substring(0, proName.Length - ".exe".Length);
            }


            //double getParentInaccuracy = GetParentInaccuracy();

            IntPtr findHwnd = IntPtr.Zero;

            NativeMethods.EnumWindows((hwnd, lParam) =>
            {
                string processName = string.Empty;

                // GetProcessName and GetWindowsName will failed due to the process for the window handle was killed.
                try
                {
                    processName = GetWndProcessName(hwnd);
                }
                catch (Exception ex)
                {
                    APP.Log.Log.Debug($"Failed to fetch process Name for window handler {hwnd}. {ex.Message}");
                }
                APP.Log.Log.Debug($"out processName:{processName},hwnd:{hwnd.ToString("x")}");

                if (processName.Equals(proName, StringComparison.CurrentCultureIgnoreCase))
                {
                    string windowName = GetWndWindowName(hwnd);
                    APP.Log.Log.Debug($"FindWindowRect out processName:{processName},hwnd:{hwnd.ToString("x")},windowName:{windowName}");

                    if (windowsTitleMatchRule.Match(windowName, winName))
                    {
                        bool found = isVisibleWindow(hwnd, includeMinimizedWindow);

                        if (found)
                        {
                            findHwnd = hwnd;
                            APP.Log.Log.Info($"FindWindowRect found processName:{processName}, 窗口 目标:{winName}, 当前:{windowName}, 匹配规则:{windowsTitleMatchRule}, findHwnd:{findHwnd}");
                        }
                        else
                        {
                            APP.Log.Log.Debug($"FindWindowRect 未找到 进程:{proName}, 窗口 目标:{winName}, 当前:{windowName}, 匹配规则:{windowsTitleMatchRule}, 包括最小化窗口?:{includeMinimizedWindow}, hwnd:{hwnd}");
                        }
                        return !found;
                    }
                    else
                    {
                        IntPtr ancestorHwnd = GetParentWindow(hwnd, getParentInaccuracy);
                        if (ancestorHwnd != IntPtr.Zero)
                        {
                            string wName = GetWndWindowName(ancestorHwnd);
                            if (windowsTitleMatchRule.Match(wName, winName))
                            {
                                bool found = isVisibleWindow(hwnd, includeMinimizedWindow);
                                if (found)
                                {
                                    findHwnd = ancestorHwnd;
                                    APP.Log.Log.Info($"FindWindowRect found ancestorHwnd processName:{processName},windowName:{windowName}, matchrule:{windowsTitleMatchRule}, findHwnd:{findHwnd}");
                                }
                                else
                                {
                                    APP.Log.Log.Debug($"FindWindowRect ancestorHwnd 父窗口也未找到, 进程:{proName}, 窗口 目标:{winName}, 当前:{wName}, 匹配规则:{windowsTitleMatchRule}, 包括最小化窗口?:{includeMinimizedWindow}, hwnd:{hwnd}, ancestorHwnd:{ancestorHwnd}");

                                }
                                return !found;
                            }
                            else
                            {
                                APP.Log.Log.Debug($"FindWindowRect 父窗口也不匹配 :{ancestorHwnd.ToString("x")}, processName:{processName}, 窗口 目标:{winName}, 当前:{windowName}, 匹配规则:{windowsTitleMatchRule}, findHwnd:{findHwnd}, hwnd:{hwnd} ");
                            }
                        }

                        return true;
                    }
                }
                else
                {
                    APP.Log.Log.Debug($"FindWindowRect processName not matched. Target:{proName}. now:{processName}");
                }

                return true;
            }, 0);

            bool isWindow;
            if (findHwnd == IntPtr.Zero)
            {
                isWindow = false;
                APP.Log.Log.Info($"not found findHwnd:{findHwnd}, wName:{winName}, matchrule:{windowsTitleMatchRule}");
            }
            else
            {
                isWindow = NativeMethods.IsWindow(findHwnd);
                if (!isWindow)
                {
                    APP.Log.Log.Error($"IsWindow false! findHwnd:{findHwnd}, wName:{winName}, matchrule:{windowsTitleMatchRule}");
                }
            }

            if (!isWindow)
            {
                return Rectangle.Empty;
            }
            winHwnd = findHwnd;
            Rectangle rectangle = GetWindowRectangle(findHwnd);
            APP.Log.Log.Debug($"findHwnd:{findHwnd.ToString("x")}");
            APP.Log.Log.Debug($"findRect:{rectangle}");
            return rectangle;
        }


        public static IntPtr GetParentWindow(IntPtr winHwnd, double getParentInaccuracy)
        {
            Rectangle hwndRectangle = Rectangle.Empty;
            Rectangle winRectangle = Rectangle.Empty;
            Rectangle interRect;
            winRectangle = GetWindowRectangle(winHwnd);
            double areaDiff, baseArea;
            do
            {
                IntPtr hwnd = NativeMethods.GetParent(winHwnd);
                if (hwnd == IntPtr.Zero)
                {
                    APP.Log.Log.Debug($"GetParent break winHwnd:{winHwnd.ToString("x")}");
                    break;
                }


                hwndRectangle = GetWindowRectangle(hwnd);
                interRect = Rectangle.Intersect(hwndRectangle, winRectangle);
                baseArea = winRectangle.Width * winRectangle.Height;
                areaDiff = interRect.Width * interRect.Height - baseArea;

                bool condition1 = Math.Abs(areaDiff / baseArea) < getParentInaccuracy;
                bool condition2 = Math.Abs(areaDiff / baseArea) < 0.6 && hwndRectangle.Width >= winRectangle.Width && hwndRectangle.Height >= winRectangle.Height;

                APP.Log.Log.Debug($"hwndRectangle:{hwndRectangle},winRectangle:{winRectangle}");
                APP.Log.Log.Debug($"condition1:{condition1},condition2:{condition2}");

                if (hwndRectangle != Rectangle.Empty && (condition1 | condition2))
                {
                    winHwnd = hwnd;
                    winRectangle = hwndRectangle;
                }
                else
                {
                    string hwndName = GetWndWindowName(hwnd);
                    APP.Log.Log.Debug($"not matched hwnd:{hwnd.ToString("x")},hwndName:{hwndName},hwndRectangle:{hwndRectangle},winRectangle:{winRectangle},winHwnd:{winHwnd.ToString("x")}");
                    break;
                }
            }
            while (true);

            return winHwnd;
        }

        public static Rectangle GetWindowRectangle(IntPtr hwnd)
        {
            try
            {
                NativeMethods.RECT rect = new NativeMethods.RECT();
                bool result = NativeMethods.GetWindowRect(hwnd, out rect);
                if (!result)
                    return Rectangle.Empty;

                return Rectangle.FromLTRB(rect.Left, rect.Top, rect.Right, rect.Bottom);
            }
            catch (Exception ex)
            {
                APP.Log.Log.Error($"GetWindowRectangle hwnd[{hwnd}] Utils0000000003 Error:{ex}");
                return Rectangle.Empty;
            }
        }
        public static string GetWndProcessName(IntPtr intPtr, out int processId)
        {
            NativeMethods.GetWindowThreadProcessId(intPtr, out processId);
            Process process = Process.GetProcessById(processId);
            if (process != null)
            {
                return process.ProcessName;
            }
            return string.Empty;
        }


        public static string GetWndProcessName(IntPtr intPtr)
        {
            int processId = 0;
            return GetWndProcessName(intPtr, out processId);
        }

        public static string GetWndWindowName(IntPtr hwnd)
        {
            if (NativeMethods.IsCurrentProcessHWnd(hwnd))
            {
                return string.Empty; // 跳过当前进程的
            }

            int length = NativeMethods.GetWindowTextLength(hwnd);
            StringBuilder sb = new StringBuilder(length + 1);
            NativeMethods.GetWindowTextSkipCurrentProcess(hwnd, sb, sb.Capacity, out bool isCurrentProcessWnd);
            return sb.ToString();
        }
        public static bool isVisibleWindow(IntPtr hwnd, bool includeMinimizedWindow)
        {
            var windowStyle = NativeMethods.GetWindowLongSTYLE(hwnd);
            bool visible = windowStyle.WS_VISIBLE && (includeMinimizedWindow || !windowStyle.WS_MINIMIZE);
            APP.Log.Log.Info($"isVisibleWindow 结果:{visible}, 可见性:{windowStyle.WS_VISIBLE}, 最小化:{windowStyle.WS_MINIMIZE}, hwnd:{hwnd}, 包括最小化窗口?:{includeMinimizedWindow}");
            return visible;
        }


    }
}
